package com.mygame

import com.almasb.fxgl.app.GameApplication
import com.almasb.fxgl.app.GameSettings
import com.almasb.fxgl.core.math.FXGLMath.randomPoint
import com.almasb.fxgl.dsl.*
import com.almasb.fxgl.dsl.FXGL.Companion.setLevelFromMap
import com.almasb.fxgl.dsl.components.HealthIntComponent
import com.almasb.fxgl.entity.Entity
import com.almasb.fxgl.entity.SpawnData
import com.almasb.fxgl.entity.components.IDComponent
import com.almasb.fxgl.entity.getComponent
import com.almasb.fxgl.input.UserAction
import com.almasb.fxgl.pathfinding.CellState
import com.almasb.fxgl.pathfinding.astar.AStarGrid
import com.mygame.components.DragComponent
import com.mygame.components.PlayerControllerComponent
import javafx.geometry.Point2D
import javafx.geometry.Rectangle2D
import javafx.scene.input.KeyCode
import javafx.scene.input.MouseButton
import javafx.scene.paint.Color
import java.util.*
import kotlin.collections.ArrayList


class KotlinApplication : GameApplication() {

    private var dragging = false
    private var path1: Entity? = null
    private var btnDownTime = 0L
    private lateinit var player: Entity
    private var dragEntity: Entity? = null
    private lateinit var playerController: PlayerControllerComponent

    override fun initSettings(settings: GameSettings) {
        with(settings) {
            width = Const.GRID_HEIGHT * Const.CELL_HEIGHT
            height = Const.GRID_HEIGHT * Const.CELL_HEIGHT
            title = "Kotlin Game - Target Practice"
            //settings.isProfilingEnabled = true  //开启FPS等信息显示
        }
    }

    override fun initInput() {
        println("initInput")
        FXGL.getInput().addAction(object : UserAction("UP") {
            override fun onAction() {
                playerController.up()
            }

            override fun onActionEnd() {
                playerController.idle()
            }
        }, KeyCode.UP)
        FXGL.getInput().addAction(object : UserAction("DOWN") {
            override fun onAction() {
                playerController.down()
            }

            override fun onActionEnd() {
                playerController.idle()
            }
        }, KeyCode.DOWN)
        FXGL.getInput().addAction(object : UserAction("LEFT") {
            override fun onAction() {
                playerController.left()
            }

            override fun onActionEnd() {
                playerController.idle()
            }
        }, KeyCode.LEFT)
        FXGL.getInput().addAction(object : UserAction("RIGHT") {
            override fun onAction() {
                playerController.right()
            }

            override fun onActionEnd() {
                playerController.idle()
            }
        }, KeyCode.RIGHT)

        onKeyDown(KeyCode.NUMPAD1, "attack") {
            playerController.attack()
        }

        onKeyDown(KeyCode.NUMPAD3, "skill1") {
            playerController.skill1()
        }

        onKeyDown(KeyCode.NUMPAD2) {
            playerController.jump()
        }

        /*FXGL.getInput().addAction(object : UserAction("shoot") {
            override fun onActionBegin() {
                btnDownTime = System.currentTimeMillis()
                playerController.clickShoot()
            }

            override fun onActionEnd() {
                if (System.currentTimeMillis() - btnDownTime > 1000) {
                    playerController.clickShoot(true)
                }
                btnDownTime = 0
            }
        }, MouseButton.PRIMARY)*/

        FXGL.getInput().addAction(object : UserAction("drag") {
            override fun onActionBegin() {

                val entities: Iterable<Entity> = getGameWorld().entities.filter {
                    it.type == EType.PATH && it.center.distance(getInput().mousePositionWorld) < it.width / 2
                }
                println("entities.position=${entities}  clickCenterPoint=${getInput().mousePositionWorld}")
                if (entities.iterator().hasNext()) {
                    val entity = entities.iterator().next()
                    println("DDDentity.position=${entity.position}  clickCenterPoint=${getInput().mousePositionWorld}")
                    dragEntity = entity
                }

            }

            override fun onAction() {
                dragEntity?.let {
                    val mp = getInput().mousePositionWorld
                    it.transformComponent.x = mp.x - it.width / 2
                    it.transformComponent.y = mp.y - it.height / 2
                }
            }

            override fun onActionEnd() {
                dragEntity = null
            }
        }, MouseButton.PRIMARY)
    }

    override fun initGame() {
        println("initGame")
        MyEntityFactory().init()
        //初始化地图
        setLevelFromMap("map_grass.tmx")
        //AI网格地图
        val grid = AStarGrid.fromWorld(
            getGameWorld(),
            Const.GRID_WIDTH,
            Const.GRID_HEIGHT,
            Const.CELL_WIDTH,
            Const.CELL_HEIGHT
        ) { type: Any -> if (type === EType.WALL) CellState.NOT_WALKABLE else CellState.WALKABLE }
        //初始化玩家
        initPlayer()
        //生成敌人
        initEnemy(grid)
        //生成地面
        initGround()
    }

    private fun initGround() {
        for (i in 0 until Const.GRID_WIDTH) {//y轴铺满条纹
            spawn(
                EType.GROUND,
                SpawnData(i * Const.CELL_WIDTH.toDouble(), 0.0)
                    .put(Const.WIDTH, Const.CELL_HEIGHT.toDouble())
                    .put(Const.HEIGHT, Const.CELL_HEIGHT * Const.GRID_HEIGHT.toDouble())
                    .put(Const.COLOR, Color(0.99, 0.3 * (1 + i % 2), 0.3 * (1 + i % 2), 0.2))
            )
        }
        for (i in 0 until Const.GRID_HEIGHT) {//x轴铺满条纹
            spawn(
                EType.GROUND,
                SpawnData(0.0, i * Const.CELL_HEIGHT.toDouble())
                    .put(Const.WIDTH, Const.CELL_WIDTH * Const.GRID_WIDTH.toDouble())
                    .put(Const.HEIGHT, Const.CELL_WIDTH.toDouble())
                    .put(Const.COLOR, Color(0.3 * (1 + i % 2), 0.99, 0.99, 0.2))

            )
        }
    }

    private fun initPlayer() {
        /*player = spawn(
            EType.PLAYER,
            SpawnData(getAppWidth() / 2.0, getAppHeight() / 2.0)
                .put(Const.RADIUS, 30.0)
                .put(Const.COLOR, Color.BLUE)
                .put(Const.HEALTH, 120)
                .put(Const.MANA, 100)
        )
        //玩家控制器
        playerController = player.getComponent<ControllerComponent>()
        //初始化相机,跟随玩家
        spawn(EType.CAMARA, SpawnData().put(Const.TAG_ENTITY, player))*/

        //使用扩展方法,EType.PLAYER2,点过去看会直接转成小写player2,拿到对应的孵化entity
        player = spawn(
            EType.PLAYER2,
            SpawnData(getAppWidth() / 2.0, getAppHeight() / 2.0)
                .put(Const.RADIUS, 40.0)
                .put(Const.COLOR, Color.BLUE)
                .put(Const.HEALTH, 120)
                .put(Const.MANA, 100)
        )

        //玩家控制器
        playerController = player.getComponent<PlayerControllerComponent>()
        //初始化相机,跟随玩家
        val camera = spawn(EType.CAMARA, SpawnData().put(Const.TAG_ENTITY, player))
    }

    private fun initEnemy(grid: AStarGrid) {
        //路径点
        val pathList = ArrayList<Entity>()
        path1 = spawn(
            EType.PATH,
            SpawnData(Const.CELL_WIDTH * 5.0, Const.CELL_HEIGHT * 2.0).put(Const.WIDTH, 40.0).put(Const.HEIGHT, 40.0)
                .put(Const.COLOR, Color.BLUEVIOLET).put(Const.NAME, "path1")
        )
        pathList.add(path1!!)
        /*val path2 = spawn(
            EType.PATH,
            SpawnData(Const.CELL_WIDTH * 12.0, Const.CELL_HEIGHT * 2.0).put(Const.WIDTH, 40.0).put(Const.HEIGHT, 40.0)
                .put(Const.COLOR, Color.BLUEVIOLET).put(Const.NAME, "path2")
        )
        pathList.add(path2)*/

        //随机区域
        val bounds = Rectangle2D(50.0, 50.0, getAppWidth() - 50.0, getAppHeight() - 50.0)
        for (i in 0..1) {
            val random = randomPoint(bounds)
            val enemy = spawn(
                EType.ENEMY,
                SpawnData(random)
                    .put(Const.RADIUS, 15.0)
                    .put(Const.COLOR, Color.AQUA)
                    .put(Const.GRID, grid)
                    .put(Const.NAME, "Enemy" + i)
                    .put(Const.PATH, pathList)
                    .put(Const.HEALTH, 100)
            )
        }
    }

    override fun initPhysics() {
        onCollisionBegin(EType.BULLET, EType.PLAYER2) { a, b ->
            a.removeFromWorld()
        }
    }

    /*override fun onUpdate(tpf: Double) {
        super.onUpdate(tpf)
        FXGL.getWorldProperties().setValue("fps", 1 / tpf)
        val mb = (1024 * 1024).toDouble()
        val freeMem = Runtime.getRuntime().freeMemory() / mb
        FXGL.getWorldProperties().setValue("freeMem", freeMem)
    }

    override fun initGameVars(vars: MutableMap<String, Any>) {
        vars.put("fps", 0.0)
        vars.put("freeMem", 0.0)
    }

    override fun initUI() {
        val fps = FXGL.getUIFactoryService().newText(FXGL.getdp("fps").asString())
        addUINode(fps, 20.0, 200.0)
        addUINode(Text( 20.0, 280.0,FXGL.getdp("fps").asString().toString()))
        val freeMem = FXGL.getUIFactoryService().newText(FXGL.getdp("freeMem").asString())
        addUINode(freeMem, 20.0, 230.0)
    }*/

    companion object {
        @JvmStatic
        fun main(args: Array<String>) {
            launch(KotlinApplication::class.java, args)
        }
    }
}
